import Vue from 'vue';
// eslint-disable-next-line no-restricted-imports
import Vuex from 'vuex';
import { GlButton } from '@gitlab/ui';
import { createWrapper } from '@vue/test-utils';
import VulnerabilityActionButtons, {
  i18n,
} from 'ee/security_dashboard/components/pipeline/vulnerability_action_buttons.vue';
import { setupStore } from 'ee/security_dashboard/store';
import { VULNERABILITY_MODAL_ID } from 'ee/vue_shared/security_reports/components/constants';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { BV_SHOW_MODAL } from '~/lib/utils/constants';
import { visitUrl } from '~/lib/utils/url_utility';
import { resetStore } from '../../helpers';
import mockDataVulnerabilities from '../../store/modules/vulnerabilities/data/mock_data_vulnerabilities';

Vue.use(Vuex);

jest.mock('~/lib/utils/url_utility', () => ({
  visitUrl: jest.fn(),
}));

describe('Security Dashboard Action Buttons', () => {
  let store;
  let wrapper;
  let dispatchMock;

  const wrapperFactory = (mountFn) => ({ ...options }) => {
    wrapper = mountFn(VulnerabilityActionButtons, {
      ...options,
      store,
    });

    dispatchMock = jest.spyOn(store, 'dispatch').mockReturnValue(Promise.resolve());
  };

  const createShallowComponent = wrapperFactory(shallowMountExtended);
  const createFullComponent = wrapperFactory(mountExtended);

  const findAllButtons = () => wrapper.findAllComponents(GlButton);
  const findMoreInfoButton = () => wrapper.findByTestId('more-info');
  const findCreateIssueButton = () => wrapper.findByTestId('create-issue');
  const findDismissVulnerabilityButton = () => wrapper.findByTestId('dismiss-vulnerability');
  const findUndoDismissButton = () => wrapper.findByTestId('undo-dismiss');

  beforeEach(() => {
    store = new Vuex.Store();
    setupStore(store);
  });

  afterEach(() => {
    resetStore(store);
  });

  describe('with a fresh vulnerability', () => {
    beforeEach(() => {
      createFullComponent({
        propsData: {
          vulnerability: mockDataVulnerabilities[0],
          canCreateIssue: true,
          canDismissVulnerability: true,
        },
      });
    });

    it('should render three buttons in a button group', () => {
      expect(findAllButtons()).toHaveLength(3);
    });

    describe('More Info Button', () => {
      it('should render the More info button', () => {
        expect(findMoreInfoButton().exists()).toBe(true);
      });

      it('should render the correct tooltip', () => {
        expect(findMoreInfoButton().attributes('title')).toBe(i18n.moreInfo);
      });

      it('should emit an `setModalData` event and open the modal when clicked', async () => {
        await findMoreInfoButton().trigger('click');

        expect(dispatchMock).toHaveBeenCalledWith('vulnerabilities/setModalData', {
          vulnerability: mockDataVulnerabilities[0],
        });

        expect(createWrapper(wrapper.vm.$root).emitted(BV_SHOW_MODAL)).toEqual([
          [VULNERABILITY_MODAL_ID],
        ]);
      });
    });

    describe('Create Issue Button', () => {
      it('should render the create issue button', () => {
        expect(findCreateIssueButton().exists()).toBe(true);
      });

      it('should render the correct tooltip', () => {
        expect(findCreateIssueButton().attributes('title')).toBe(i18n.createIssue);
      });

      it('should emit an `createIssue` event when clicked', async () => {
        await findCreateIssueButton().trigger('click');

        expect(dispatchMock).toHaveBeenCalledWith('vulnerabilities/createIssue', {
          vulnerability: mockDataVulnerabilities[0],
          flashError: true,
        });
      });

      describe('with Jira issues for vulnerabilities enabled', () => {
        beforeEach(() => {
          createFullComponent({
            propsData: {
              vulnerability: mockDataVulnerabilities[8],
              canCreateIssue: true,
            },
          });
        });

        it('should render the correct tooltip', () => {
          expect(findCreateIssueButton().attributes('title')).toBe(i18n.createJiraIssue);
        });

        it('should open a new window when the create-issue button is clicked', async () => {
          expect(visitUrl).not.toHaveBeenCalled();

          await findCreateIssueButton().trigger('click');

          expect(visitUrl).toHaveBeenCalledWith(
            mockDataVulnerabilities[8].create_jira_issue_url,
            true, // external link flag
          );
        });
      });
    });

    describe('Dismiss Vulnerability Button', () => {
      it('should render the dismiss vulnerability button', () => {
        expect(findDismissVulnerabilityButton().exists()).toBe(true);
      });

      it('should render the correct tooltip', () => {
        expect(findDismissVulnerabilityButton().attributes('title')).toBe(
          i18n.dismissVulnerability,
        );
      });

      it('should emit an `dismissVulnerability` event when clicked', async () => {
        await findDismissVulnerabilityButton().trigger('click');

        expect(dispatchMock).toHaveBeenCalledWith('vulnerabilities/dismissVulnerability', {
          vulnerability: mockDataVulnerabilities[0],
          flashError: true,
        });
      });
    });
  });

  describe('with a vulnerability that has an issue', () => {
    beforeEach(() => {
      createShallowComponent({
        propsData: {
          vulnerability: mockDataVulnerabilities[3],
        },
      });
    });

    it('should only render one button', () => {
      expect(findAllButtons()).toHaveLength(1);
    });

    it('should not render the create issue button', () => {
      expect(findCreateIssueButton().exists()).toBe(false);
    });
  });

  describe('with a vulnerability that has been dismissed', () => {
    beforeEach(() => {
      createShallowComponent({
        propsData: {
          vulnerability: mockDataVulnerabilities[2],
          canDismissVulnerability: true,
          isDismissed: true,
        },
      });
    });

    it('should render two buttons in a button group', () => {
      expect(findAllButtons()).toHaveLength(2);
    });

    it('should not render the dismiss vulnerability button', () => {
      expect(findDismissVulnerabilityButton().exists()).toBe(false);
    });

    it('should render the undo dismiss button', () => {
      expect(findUndoDismissButton().exists()).toBe(true);
    });

    it('should render the correct tooltip', () => {
      expect(findUndoDismissButton().attributes('title')).toBe(i18n.revertDismissVulnerability);
    });
  });
});
